home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / emacssrc.zip / EMACSSRC.TAR / emacs-19.17 / src / ntterm.c < prev    next >
C/C++ Source or Header  |  1993-11-22  |  15KB  |  645 lines

  1. /*
  2.    Terminal hooks for Windows NT(tm) port of GNU Emacs.
  3.    Copyright (C) 1992 Free Software Foundation, Inc.
  4.  
  5.    This file is part of GNU Emacs.
  6.  
  7.    GNU Emacs is free software; you can redistribute it and/or modify it
  8.    under the terms of the GNU General Public License as published by the
  9.    Free Software Foundation; either version 1, or (at your option) any later
  10.    version.
  11.  
  12.    GNU Emacs is distributed in the hope that it will be useful, but WITHOUT
  13.    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14.    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  15.    more details.
  16.  
  17.    You should have received a copy of the GNU General Public License along
  18.    with GNU Emacs; see the file COPYING.  If not, write to the Free Software
  19.    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  
  21.    Tim Fleehart (apollo@online.com)        17-Jan-92
  22.    Geoff Voelker (voelker@cs.washington.edu)    9-12-93   (updated to vers. 19)
  23. */
  24.  
  25.  
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28.  
  29. #include "config.h"
  30.  
  31. #include <windows.h>
  32.  
  33. #include "lisp.h"
  34. #include "frame.h"
  35. #include "disptab.h"
  36. #include "termhooks.h"
  37.  
  38. #include "ntterm_p.h"
  39. #include "ntinevt_p.h"
  40. #include "alloca_p.h"
  41.  
  42. extern FRAME_PTR updating_frame;
  43.  
  44. extern int meta_key;
  45.  
  46. static void MoveCursor(int row, int col);
  47. static void ClearToEnd(void);
  48. static void ClearFrame(void);
  49. static void ClearEndOfLine(int);
  50. static void InsDelLines(int vpos, int n);
  51. static void ChangeLineHighlight(int, int, int);
  52. static void ReassertLineHighlight(int, int);
  53. static void InsertGlyphs(GLYPH *start, int len);
  54. static void WriteGlyphs(GLYPH *string, int len);
  55. static void DeleteGlyphs(int n);
  56. static void RingBell(void);
  57. static void ResetTerminalModes(void);
  58. static void SetTerminalModes(void);
  59. static void SetTerminalWindow(int size);
  60. static void UpdateBegin(FRAME_PTR f);
  61. static void UpdateEnd(FRAME_PTR f);
  62. static void ResetKbd(void);
  63. static void UnsetKbd(void);
  64. static int HLmode(int new_highlight);
  65.  
  66. /*
  67.    Init hook called in init_keyboard
  68.    */
  69. void (*keyboard_init_hook)(void) = ResetKbd;
  70.     
  71. COORD    Cursor;
  72. HANDLE    PrevScreen, CurScreen;
  73. UCHAR    CAttr, CAttrNormal, CAttrReverse;
  74. HANDLE  Keyboard;
  75.  
  76. /*
  77.  * CtrlCHandler for Windows NT (tm)
  78.  *
  79.  * Setting this as the ctrl handler prevents emacs from being killed when
  80.  * someone hits ^C in a 'suspended' session (child shell).
  81.  */
  82.  
  83. BOOL WINAPI
  84. CtrlCHandler(DWORD type)
  85. {
  86.     if (type == CTRL_C_EVENT) {
  87.         return TRUE;
  88.     } else {
  89.         return FALSE;
  90.     }
  91. }
  92.  
  93. /*
  94.    If we're updating a frame, use it as the current frame
  95.    Otherwise, use the selected frame
  96.    */
  97. #define PICK_FRAME() (updating_frame ? updating_frame : selected_frame)
  98.  
  99. /*
  100.  * move the cursor to (row, col)
  101.  */
  102. void
  103. MoveCursor(int row, int col)
  104. {
  105.     Cursor.X = col;
  106.     Cursor.Y = row;
  107.  
  108.     if (updating_frame == NULL)
  109.     {
  110.         SetConsoleCursorPosition(CurScreen, Cursor);
  111.     }
  112. }
  113.  
  114. /*
  115.  * clear from cursor to end of screen
  116.  */
  117. void
  118. ClearToEnd(void)
  119. {
  120.     FRAME_PTR f = PICK_FRAME();
  121.  
  122.     ClearEndOfLine(FRAME_WIDTH(f) - 1);
  123.  
  124.     InsDelLines(Cursor.Y, FRAME_HEIGHT(f) - Cursor.Y - 1);
  125. }
  126.  
  127. /*
  128.  * clear the frame
  129.  */
  130. void
  131. ClearFrame(void)
  132. {
  133.     SMALL_RECT    Scroll;
  134.     COORD    Dest;
  135.     CHAR_INFO    Fill;
  136.     FRAME_PTR   f = PICK_FRAME();
  137.  
  138.     HLmode(0);
  139.  
  140.     Scroll.Top = 0;
  141.     Scroll.Bottom = FRAME_HEIGHT(f) - 1;
  142.     Scroll.Left = 0;
  143.     Scroll.Right = FRAME_WIDTH(f) - 1;
  144.  
  145.     Dest.Y = FRAME_HEIGHT(f);
  146.     Dest.X = 0;
  147.  
  148.     Fill.Char.AsciiChar = 0x20;
  149.     Fill.Attributes = CAttr;
  150.  
  151.     ScrollConsoleScreenBuffer(CurScreen, &Scroll, NULL, Dest, &Fill);
  152.  
  153.     MoveCursor(0, 0);
  154. }
  155.  
  156.  
  157. /*
  158.  * clear from Cursor to end (what's "standout marker"?)
  159.  */
  160. void
  161. ClearEndOfLine(int end)
  162. {
  163.     static  GLYPH   base[256];
  164.     static  BOOL    beenhere = FALSE;
  165.  
  166.     if (!beenhere)
  167.     {
  168.         int    i;
  169.  
  170.         for (i = 0; i < 256; i++)
  171.         {
  172.             base[i] = SPACEGLYPH;        /* empty space    */
  173.         }
  174.  
  175.         beenhere = TRUE;
  176.     }
  177.  
  178.     WriteGlyphs(base, end - Cursor.X);    /* fencepost ?    */
  179. }
  180.  
  181. /*
  182.  * insert n lines at vpos. if n is negative delete -n lines
  183.  */
  184. void
  185. InsDelLines(int vpos, int n)
  186. {
  187.     int        i, nb, save_highlight;
  188.     SMALL_RECT    Scroll;
  189.     COORD    Dest;
  190.     CHAR_INFO    Fill;
  191.     FRAME_PTR f = PICK_FRAME();
  192.  
  193.     if (n < 0)
  194.     {
  195.         Scroll.Top = vpos - n;
  196.         Scroll.Bottom = FRAME_HEIGHT(f);
  197.         Dest.Y = vpos;
  198.     }
  199.     else
  200.     {
  201.         Scroll.Top = vpos;
  202.         Scroll.Bottom = FRAME_HEIGHT(f) - n;
  203.         Dest.Y = vpos + n;
  204.     }
  205.     Scroll.Left = 0;
  206.     Scroll.Right = FRAME_WIDTH(f);
  207.  
  208.     Dest.X = 0;
  209.  
  210.     save_highlight = HLmode(0);
  211.  
  212.     Fill.Char.AsciiChar = 0x20;
  213.     Fill.Attributes = CAttr;
  214.  
  215.     ScrollConsoleScreenBuffer(CurScreen, &Scroll, NULL, Dest, &Fill);
  216.  
  217.     /*
  218.      * here we have to deal with a win32 console flake: If the scroll
  219.      * region looks like abc and we scroll c to a and fill with d we get
  220.      * cbd... if we scroll block c one line at a time to a, we get cdd...
  221.      * Jove expects cdd consistently... So we have to deal with that
  222.      * here... (this also occurs scrolling the same way in the other
  223.      * direction.
  224.      */
  225.  
  226.     if (n > 0)
  227.     {
  228.         if (Scroll.Bottom < Dest.Y)
  229.         {
  230.             for (i = Scroll.Bottom; i < Dest.Y; i++)
  231.             {
  232.                 MoveCursor(i, 0);
  233.                 ClearEndOfLine(FRAME_WIDTH(f));
  234.             }
  235.         }
  236.     }
  237.     else
  238.     {
  239.         nb = Dest.Y + (Scroll.Bottom - Scroll.Top) + 1;
  240.  
  241.         if (nb < Scroll.Top)
  242.         { 
  243.             for (i = nb; i < Scroll.Top; i++)
  244.             {
  245.                 MoveCursor(i, 0);
  246.                 ClearEndOfLine(FRAME_WIDTH(f));
  247.             }
  248.         }
  249.     }
  250.  
  251.     Cursor.X = 0;
  252.     Cursor.Y = vpos;
  253.  
  254.     HLmode(save_highlight);
  255. }
  256.  
  257.  
  258. /*
  259.  * HLmode -- Changes attribute to use when drawing characters to control
  260.  * highlighting
  261.  */
  262. static int
  263. HLmode(int new_highlight)
  264. {
  265.     static int Highlight = 0;
  266.     int old_highlight;
  267.  
  268.     old_highlight = Highlight;
  269.     Highlight = (new_highlight != 0);    /* map to boolean */
  270.     if (Highlight)
  271.     {
  272.         CAttr = CAttrReverse;
  273.     }
  274.     else
  275.     {
  276.         CAttr = CAttrNormal;
  277.     }
  278.     return old_highlight;
  279. }
  280.  
  281. /*
  282.  * Call this when about to modify line at position VPOS and change whether it
  283.  * is highlighted.
  284.  */
  285. void
  286. ChangeLineHighlight(int new_highlight, int vpos, int first_unused_hpos)
  287. {
  288.     HLmode(new_highlight);
  289.     MoveCursor(vpos, 0);
  290.     ClearEndOfLine(first_unused_hpos);
  291. }
  292.  
  293. /*
  294.  * External interface to control of standout mode. Call this when about to
  295.  * modify line at position VPOS and not change whether it is highlighted.
  296.  */
  297. void
  298. ReassertLineHighlight(int highlight, int vpos)
  299. {
  300.     HLmode(highlight);
  301.     vpos;            /* pedantic compiler silencer */
  302. }
  303.  
  304. #undef    LEFT
  305. #undef    RIGHT
  306. #define    LEFT    1
  307. #define    RIGHT    0
  308.  
  309. void
  310. ScrollLine(int dist, int direction)
  311. {
  312.     /*
  313.      * The idea here is to implement a horizontal scroll in one line to
  314.      * implement delete and half of insert.
  315.      */
  316.     SMALL_RECT    Scroll;
  317.     COORD    Dest;
  318.     CHAR_INFO    Fill;
  319.     FRAME_PTR f = PICK_FRAME();
  320.  
  321.     Scroll.Top = Cursor.Y;
  322.     Scroll.Bottom = Cursor.Y;
  323.  
  324.     if (direction == LEFT)
  325.     {
  326.         Scroll.Left = Cursor.X+dist;
  327.         Scroll.Right = FRAME_WIDTH(f)-1;
  328.     }
  329.     else
  330.     {
  331.         Scroll.Left = Cursor.X;
  332.         Scroll.Right = FRAME_WIDTH(f)-dist-1;
  333.     }
  334.  
  335.     Dest.X = Cursor.X;
  336.     Dest.Y = Cursor.Y;
  337.  
  338.     Fill.Char.AsciiChar = 0x20;
  339.     Fill.Attributes = CAttr;
  340.     
  341.     ScrollConsoleScreenBuffer(CurScreen, &Scroll, NULL, Dest, &Fill);
  342. }
  343.  
  344.  
  345. /*
  346.  * if start is zero insert blanks instead of a string at start ?
  347.  */
  348. void
  349. InsertGlyphs(register GLYPH *start, register int len)
  350. {
  351.     ScrollLine(len, RIGHT);
  352.  
  353.     /*
  354.      * move len chars to the right starting at Cursor, fill with blanks
  355.      */
  356.     if (start)
  357.     {
  358.     /*
  359.      * print the first len characters of start, Cursor.X adjusted
  360.      * by WriteGlyphs.
  361.      */
  362.     
  363.     WriteGlyphs(start, len);
  364.     }
  365.     else
  366.     {
  367.         ClearEndOfLine(Cursor.X + len);
  368.     }
  369. }
  370.  
  371. void
  372. WriteGlyphs(register GLYPH *string, register int len)
  373. {
  374.     register char *ptr;
  375.     register unsigned int glyphLength = GLYPH_TABLE_LENGTH;
  376.     Lisp_Object *glyphBase = GLYPH_TABLE_BASE;
  377.     int i;
  378.     GLYPH glyph;
  379.     FRAME_PTR f = PICK_FRAME();
  380.     WORD *attrs;
  381.     char *chars;
  382.  
  383.     attrs = alloca(len*sizeof(*attrs));
  384.     chars = alloca(len*sizeof(*chars));
  385.     if (attrs == NULL || chars == NULL)
  386.     {
  387.         printf("alloca failed in WriteGlyphs\n");
  388.         return;
  389.     }
  390.  
  391.     /*
  392.      * We have to deal with the glyph indirection...go over the glyph
  393.      * buffer and extract the characters.
  394.      */
  395.     ptr = chars;
  396.     while (--len >= 0)
  397.     {
  398.     glyph = *string++;
  399.  
  400.     if (glyph > glyphLength)
  401.         {
  402.         *ptr++ = glyph & 0xFF;
  403.         continue;
  404.     }
  405.     GLYPH_FOLLOW_ALIASES(glyphBase, glyphLength, glyph);
  406.     if (GLYPH_FACE(glyph) != 0)
  407.         printf("Glyph face is %d\n", GLYPH_FACE(glyph));
  408.     if (GLYPH_SIMPLE_P(glyphBase, glyphLength, glyph))
  409.         {
  410.         *ptr++ = glyph & 0xFF;
  411.         continue;
  412.     }
  413.     for (i = 0; i < GLYPH_LENGTH(glyphBase, glyph); i++)
  414.         {
  415.         *ptr++ = (GLYPH_STRING(glyphBase, glyph))[i];
  416.     }
  417.     }
  418.  
  419.     /* Number of characters we have in the buffer */
  420.     len = ptr-chars;
  421.     
  422.     /*
  423.      * Fill in the attributes for these characters.
  424.      */
  425.     memset(attrs, CAttr, len*sizeof(*attrs));
  426.  
  427.     /*
  428.      * Write the attributes.
  429.      */
  430.     if (!WriteConsoleOutputAttribute(CurScreen, attrs, len, Cursor, &i))
  431.     {
  432.     printf("Failed writing console attributes.\n");
  433.     fflush(stdout);
  434.     }
  435.     /*
  436.      * Write the characters.
  437.      */
  438.     if (!WriteConsoleOutputCharacter(CurScreen, chars, len, Cursor, &i))
  439.     {
  440.     printf("Failed writing console characters.\n");
  441.     fflush(stdout);
  442.     }
  443.  
  444.     Cursor.X += len;
  445.     MoveCursor(Cursor.Y, Cursor.X);
  446. }
  447.  
  448. void
  449. DeleteGlyphs(int n)
  450. {
  451.     /*
  452.      * delete chars means scroll chars from Cursor.X + n to Cursor.X,
  453.      * anything beyond the edge of the screen should come out empty...
  454.      */
  455.     ScrollLine(n, LEFT);
  456. }
  457.  
  458. void
  459. RingBell(void)
  460. {
  461.     Beep(666, 100);        /* wha'da-ya-want-fer-nothin'?    */
  462. }
  463.  
  464. /* Reset to the original console mode but don't get rid of our console
  465.    For suspending emacs */
  466. void
  467. RestoreConsole(void)
  468. {
  469.     UnsetKbd();
  470.     SetConsoleActiveScreenBuffer(PrevScreen);
  471. }
  472.  
  473. /* Put our console back up, for ending a suspended session */
  474. void
  475. TakeConsole(void)
  476. {
  477.     ResetKbd();
  478.     SetConsoleActiveScreenBuffer(CurScreen);
  479. }
  480.    
  481. void
  482. ResetTerminalModes(void)
  483. {
  484.     UnsetKbd();
  485.  
  486.     SetConsoleActiveScreenBuffer(PrevScreen);
  487.  
  488.     CloseHandle(CurScreen);
  489.     
  490.     CurScreen = NULL;
  491. }
  492.  
  493. void
  494. SetTerminalModes(void)
  495. {
  496.     CONSOLE_CURSOR_INFO cci;
  497.  
  498.     if (CurScreen == NULL)
  499.     {
  500.     ResetKbd();
  501.  
  502.     CurScreen = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
  503.                                               0, NULL,
  504.                                               CONSOLE_TEXTMODE_BUFFER,
  505.                                               NULL);
  506.  
  507.     if (CurScreen == INVALID_HANDLE_VALUE)
  508.         {
  509.             printf("CreateConsoleScreenBuffer failed in ResetTerm\n");
  510.             printf("LastError = 0x%lx\n", GetLastError());
  511.  
  512.             printf("CreateConsoleScreenBuffer failed in ResetTerm\n");
  513.             printf("LastError = 0x%lx\n", GetLastError());
  514.             
  515.             fflush(stdout);
  516.  
  517.             exit(0);
  518.     }
  519.  
  520.     SetConsoleActiveScreenBuffer(CurScreen);
  521.  
  522.     /* make cursor big and visible */
  523.         cci.dwSize = 100;
  524.         cci.bVisible = TRUE;
  525.         (void) SetConsoleCursorInfo(CurScreen, &cci);
  526.     }
  527. }
  528.  
  529. /*
  530.  * hmmm... perhaps these let us bracket screen changes so that we can flush
  531.  * clumps rather than one-character-at-a-time...
  532.  *
  533.  * we'll start with not moving the cursor while an update is in progress
  534.  */
  535. void
  536. UpdateBegin(FRAME_PTR f)
  537. {
  538. }
  539.  
  540. void
  541. UpdateEnd(FRAME_PTR f)
  542. {
  543.     SetConsoleCursorPosition(CurScreen, Cursor);
  544. }
  545.  
  546. void
  547. SetTerminalWindow(int size)
  548. {
  549. }
  550.  
  551. void
  552. UnsetKbd(void)
  553. {
  554.     SetConsoleMode(Keyboard, ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
  555.                    ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT);
  556. }
  557.  
  558. void
  559. ResetKbd(void)
  560. {
  561.     Keyboard = GetStdHandle(STD_INPUT_HANDLE);
  562.  
  563.     SetConsoleMode(Keyboard, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
  564. }
  565.  
  566. void
  567. initialize_win_nt_display(void)
  568. {
  569.     CONSOLE_SCREEN_BUFFER_INFO    Info;
  570.  
  571.     cursor_to_hook        = MoveCursor;
  572.     raw_cursor_to_hook        = MoveCursor;
  573.     clear_to_end_hook        = ClearToEnd;
  574.     clear_frame_hook        = ClearFrame;
  575.     clear_end_of_line_hook    = ClearEndOfLine;
  576.     ins_del_lines_hook        = InsDelLines;
  577.     change_line_highlight_hook    = ChangeLineHighlight;
  578.     reassert_line_highlight_hook= ReassertLineHighlight;
  579.     insert_glyphs_hook        = InsertGlyphs;
  580.     write_glyphs_hook        = WriteGlyphs;
  581.     delete_glyphs_hook        = DeleteGlyphs;
  582.     ring_bell_hook        = RingBell;
  583.     reset_terminal_modes_hook    = ResetTerminalModes;
  584.     set_terminal_modes_hook    = SetTerminalModes;
  585.     set_terminal_window_hook    = SetTerminalWindow;
  586.     update_begin_hook        = UpdateBegin;
  587.     update_end_hook        = UpdateEnd;
  588.  
  589.     read_socket_hook = Win32ReadSocket;
  590.     mouse_position_hook = Win32MousePosition;
  591.     
  592.     PrevScreen = GetStdHandle(STD_OUTPUT_HANDLE);
  593.  
  594.     SetTerminalModes();
  595.  
  596.     GetConsoleScreenBufferInfo(CurScreen, &Info);
  597.  
  598.     meta_key = 1;
  599.     CAttr = Info.wAttributes & 0xFF;
  600.     CAttrNormal = CAttr;
  601.     CAttrReverse = ((CAttr & 0xf) << 4) + ((CAttr & 0xf0) >> 4);
  602.  
  603.     FRAME_HEIGHT(selected_frame) = Info.dwSize.Y;    /* lines per page */
  604.     FRAME_WIDTH(selected_frame) = Info.dwSize.X;  /* characters per line */
  605.  
  606.     MoveCursor(0, 0);
  607.  
  608.     ClearFrame();
  609. }
  610.  
  611. DEFUN_P(Fset_screen_color, (Lisp_Object foreground, Lisp_Object background));
  612. DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
  613.        "Set screen colors.")
  614.     (foreground, background)
  615.     Lisp_Object foreground;
  616.     Lisp_Object background;
  617. {
  618.     CAttrNormal = XFASTINT(foreground) + (XFASTINT(background) << 4);
  619.     CAttrReverse = XFASTINT(background) + (XFASTINT(foreground) << 4);
  620.  
  621.     Frecenter (Qnil);
  622.     return Qt;
  623. }
  624.  
  625. DEFUN_P(Fset_cursor_size, (Lisp_Object size));
  626. DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0,
  627.        "Set cursor size.")
  628.     (size)
  629.     Lisp_Object size;
  630. {
  631.     CONSOLE_CURSOR_INFO cci;
  632.     cci.dwSize = XFASTINT(size);
  633.     cci.bVisible = TRUE;
  634.     (void) SetConsoleCursorInfo(CurScreen, &cci);
  635.  
  636.     return Qt;
  637. }
  638.  
  639. _VOID_
  640. syms_of_ntterm ()
  641. {
  642.     defsubr(&Sset_screen_color);
  643.     defsubr(&Sset_cursor_size);
  644. }
  645.